/*
 * 代号：凤凰
 * http://www.jphenix.org
 * 2017年1月12日
 * V4.0
 */
package com.jphenix.kernel.script;

import com.jphenix.share.lang.SDate;
import com.jphenix.share.lang.SInteger;
import com.jphenix.share.lang.SLong;
import com.jphenix.share.util.BaseUtil;
import com.jphenix.standard.docs.ClassInfo;
import com.jphenix.standard.script.IScriptNoManager;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * 内部脚本编码处理类
 * 
 * 2019-06-18 不考虑已删除的脚本编号再次使用，容易出问题，比如以前有程序调用了已删除的脚本。后来就变成了调用新建的脚本了
 *            增加了toString方法
 *            增加了最后变动时间，用于观察集群代码同步
 *            
 * @author MBG
 * 2017年1月12日
 */
@ClassInfo({"2019-06-18 12:51","内部脚本编码处理类"})
public class NativeScriptNoManager implements IScriptNoManager {
	
	//当前最大脚本主键
	private Map<String,String> maxScriptIdMap = new HashMap<String,String>();

	private long lastChangeTime = System.currentTimeMillis(); //上次发生变化的时间
	
	
	/**
	 * 构造函数
	 * @author MBG
	 */
	public NativeScriptNoManager() {
		super();
	}

    /**
     * 获取新的编号
     * @param header 脚本头代码
     * @return 新的脚本编号
     * 2016年3月15日
     * @author 马宝刚
     */
	@Override
	public String create(String header) {
	    if(header==null) {
	        header = "";
	    }else {
	        header = header.trim();
	    }
	    int maxId; //当前头的最大值
	    synchronized (maxScriptIdMap) {
	        //当前头
            maxId = SInteger.valueOf(maxScriptIdMap.get(header))+1;
            maxScriptIdMap.put(header,String.valueOf(maxId));
        }
	    //构建返回值
        String reStr = String.valueOf(maxId);
        //确定脚本代码必须大于6位
        while(reStr.length()<6) {
            reStr = "0"+reStr;
        }
        lastChangeTime = System.currentTimeMillis();
        return header+reStr;
	}
	
    /**
     * 删除脚本编号
     * 不考虑已删除的编号再次使用
     * @param scriptId 脚本编号
     * 2016年3月15日
     * @author 马宝刚
     */
	@Override
	public void delete(String scriptId) {}
	

    /**
     * 启动后通知服务端，本地最大的编号
     * @param scriptIdMap  key脚本头，value最大编号
     * 2016年3月15日
     * @author 马宝刚
     */
	@Override
	public void setMaxId(Map<String, String> scriptIdMap) {
		if(scriptIdMap==null) {
			return;
		}
		this.maxScriptIdMap = scriptIdMap;
		lastChangeTime      = System.currentTimeMillis();
	}
	
    /**
     * 设置本地最大的编号
     * @param header 脚本头  可能也是完整的脚本编号
     * @param maxId  最大编号
     * 2016年3月15日
     * @author 马宝刚
     */
	@Override
    public void setMaxId(String header,String maxId) {
		//分离出脚本头0和脚本编号1
		String[] infos = getScriptCode(header);
		//当前最大值
		long thisLong = SLong.valueOf(maxScriptIdMap.get(infos[0]));
		if(thisLong<SLong.valueOf(maxId)) {
			maxScriptIdMap.put(infos[0],maxId);
			lastChangeTime = System.currentTimeMillis();
		}
    }
	
	
    /**
     * 设置本地最大的编号
     * @param scriptId 脚本编号
     * 2016年3月15日
     * @author 马宝刚
     */
	@Override
	public void setMaxid(String scriptId) {
		//分离出脚本头0和脚本编号1
		String[] infos = getScriptCode(scriptId);
		//当前最大值
		long thisLong = SLong.valueOf(maxScriptIdMap.get(infos[0]));
		if(thisLong<SLong.valueOf(infos[1])) {
			maxScriptIdMap.put(infos[0],infos[1]);
			lastChangeTime = System.currentTimeMillis();
		}
	}
	
	/**
	 * 统计脚本最大主键值
	 * @param scriptMap 脚本容器
	 * 2017年1月12日
	 * @author MBG
	 */
	@Override
	public void setMaxIds(Map<String,ScriptVO> scriptMap) {
		//获取脚本主键序列
		List<String> scriptIdList = BaseUtil.getMapKeyList(scriptMap);
		for(String scriptId:scriptIdList) {
			setMaxid(scriptId);
		}
		lastChangeTime = System.currentTimeMillis();
	}

    /**
     * 获取统一的版本编号
     * 不同的服务器的时间一致，会导致新旧版本判断的失误
     * @return
     * 2016年6月16日
     * @author MBG
     */
	@Override
	public String newVer() {
		return SDate.nowDateTimeWithoutSecond();
	}

	
	/**
	 * 通过脚本名称，剥离出脚本头和脚本代码
	 * @param name 脚本名
	 * @return 字符串数组 0脚本头   1脚本代码
	 * 2015年2月25日
	 * @author 马宝刚
	 */
	protected String[] getScriptCode(String name) {
        //构建返回值
        String[] res = new String[2];
        if(name==null || name.length()<1) {
            res[0] = "";
            res[1] = "";
            return res;
        }
        //生成字节
        byte[] nameBytes = name.getBytes();
        int endPoint = nameBytes.length-1; //结束索引（除去末尾字母）
        while(endPoint>=0 && !(nameBytes[endPoint]>='0' && nameBytes[endPoint]<='9')) {
        	endPoint--;
        }
        if(endPoint<0) {
        	//整个脚本名都是字母
            res[0] = name;
            res[1] = "";
            return res;
        }
        int point = 0; //分割点
        while(!(nameBytes[point]>='0' && nameBytes[point]<='9')) {
            point ++;
            if(point>=endPoint) {
                res[0] = "";
                res[1] = "";
                return res;
            }
        }
        if(point>=endPoint) {
            res[0] = "";
            res[1] = name;
            return res;
        }
        res[0] = new String(nameBytes,0,point);
        res[1] = new String(nameBytes,point,endPoint-point+1);
        return res;
    }
	
	/**
	 * 覆盖方法
	 */
	@Override
    public String toString() {
		//构建返回值
		StringBuffer reSbf = new StringBuffer("NativeScriptNoManager:\n");
		
		reSbf
		   .append("LastChangeTime:[").append(SDate.getTs(lastChangeTime)).append("] KeepTime:[")
		   .append(SDate.showMillisecond(System.currentTimeMillis()-lastChangeTime)).append("]\n");
		
		//主键迭代
		Iterator<String> keyIter = maxScriptIdMap.keySet().iterator();
		String key; //主键元素
		while(keyIter.hasNext()) {
			key = keyIter.next();
			reSbf.append("[").append(key).append("] MaxID:[").append(maxScriptIdMap.get(key)).append("]\n");
		}
		return reSbf.toString();
	}
}
